﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JetBrains.Annotations;
using UnityEngine;

namespace CxExtension
{
	public static class IListExt
	{

		public static void ConvertAllE<T, T2>(this IList<T> self, IList<T2> outList, Func<T, T2> converter)
		{
			self.ConvertAll(outList, (it, i) => converter(it));
		}

		public static void ConvertAll<T, T2>(this IList<T> self,IList<T2> outList, Func<T, int, T2> converter)
		{
			for (var i = 0; i < self.Count; i++)
			{
				var it = self[i];
				var nit = converter(it, i);
				outList.Add(nit);
			}

		}
		public static List<T2> ConvertAll<T, T2>(this IList<T> self, Func<T, T2> converter)
		{
			var lst = new List<T2>();
			self.ConvertAllE(lst, converter);
			return lst;
		}
		public static List<T2> ConvertAll<T, T2>(this IList<T> self, Func<T, int, T2> converter)
		{
			var lst = new List<T2>();
			self.ConvertAll(lst, converter);
			return lst;
		}
		public static void AddRange<T>(this IList<T> list, IList<T> adds, int count)
		{
			var length = Math.Min(count, adds.Count);
			for (var i = 0; i < length; i++)
			{
				list.Add(adds[i]);
			}
		}
		public static void ForEach<T>(this IList<T> self, Action<T> func)
		{
			self.ForEach(func, 0, self.Count);
		}

		public static int IndexOf<T>(this IList<T> self, Func<T, bool> func, int start, int count)
		{
			var length = start + count;
			for (var i = start; i < length; i++)
			{
				var it = self[i];
				if (func(it))
				{
					return i;
				}
			}

			return -1;
		}

		public static int IndexOf<T>(this IList<T> self, Func<T, bool> func)
		{
			return self.IndexOf(func, 0, self.Count);
		}

		public static void ForEach_r<T>([NotNull] this IList<T> self, [NotNull] Action<T> func, int start, int count)
		{
			count = Mathfe.ClampRing0(count, self.Count);
			self.ForEach(func, start, start + count);
		}
		public static void ForEach<T>([NotNull] this IList<T> self, [NotNull] Action<T> func, int start, int end)
		{
			if (func == null) throw new ArgumentNullException("func");

			self.ForEachi((it, i) => func(it), start, end);
		}

		public static void ForEachi<T>([NotNull] this IList<T> self, Action<T, int> func)
		{
			if (self == null) throw new ArgumentNullException("self");

			self.ForEachi(func, 0, self.Count);
		}
		public static void ForEachi<T>(this IList<T> self, Action<T, int> func, int start, int end)
		{
			if (self == null) throw new ArgumentNullException("self");
			if (func == null) throw new ArgumentNullException("func");
			if (start < 0) throw new ArgumentOutOfRangeException("start:" + start);
			if (end > self.Count) throw new ArgumentOutOfRangeException("end:" + end);
			end = Mathfe.ClampRing(end, 0, self.Count);

			for (var i = start; i < end; i++)
			{
				func(self[i], i);
			}
		}
		public static void ForEachBreakOnTrue<T>(this IList<T> self, Func<T, bool> func)
		{
			var len = self.Count;
			for (var i = 0; i < len; i++)
			{
				var it = self[i];
				if (func(it))
				{
					break;
				}
			}
		}

		public static T Get<T>(this IList<T> self, int indx)
		{
			return self.Get(indx, true);
		}
		/// <summary>
		/// 取得某个索引的值 如果往上越界就取最后的元素,往下越界就去最前的元素
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="list"></param>
		/// <param name="indx"></param>
		/// <returns></returns>
		public static T Get<T>(this IList<T> list, int indx,bool loged)
		{
			var count = list.Count;
			if (count > 0)
			{
				if (indx < count) return list[indx];

				indx = count - 1;
				if (loged)
				{
					Debug.LogWarningFormat("数组越界了!count ={0},indx = {1}", count, indx);
				}
				return list[indx];
			}

			//Debug.LogWarningFormat("一个元素都没有 还要去索引{0}的值", indx);
			return default(T);
		}

		public static T GetOrNew<T>(this IList<T> self, Predicate<T> func) where T : new()
		{
			return self.GetOrNew(func, () => new T());
		}

		public static T GetOrNew<T>(this IList<T> self, Predicate<T> func, Func<T> newAction)
		{
			T t;
			if (self.FindA(func, out t)) return t;

			t = newAction();
			self.Add(t);

			return t;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="K"></typeparam>
		/// <typeparam name="T"></typeparam>
		/// <param name="self"></param>
		/// <param name="keyFunc">input value return key</param>
		/// <param name="dic"></param>
		/// <returns></returns>
		public static Dictionary<K, T> ToDictionary<K, T>(this IList<T> self, Func<T, K> keyFunc, Dictionary<K, T> dic)
		{
			if (self == null) throw new ArgumentNullException("self");
			if (keyFunc == null) throw new ArgumentNullException("keyFunc");
			if (dic == null) throw new ArgumentNullException("dic");

			self.ForEach(it =>
			{
				var k = keyFunc(it);
				dic.Add(k, it);
			});
			return dic;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="K"></typeparam>
		/// <typeparam name="T"></typeparam>
		/// <param name="self"></param>
		/// <param name="keyFunc">input value return key</param>
		/// <returns></returns>
		public static Dictionary<K, T> ToDictionary<K, T>(this IList<T> self, Func<T, K> keyFunc)
		{
			var dic = new Dictionary<K, T>();
			return self.ToDictionary(keyFunc, dic);
		}
		public static string ToStringAllItem<T>(this IList<T> self)
		{
			var sb = new StringBuilder();
			self.ForEach(it => sb.AppendLine(it.ToString()));
			return sb.ToString();
		}
		public static string ToStringAllItem<T>(this IList<T> self, [NotNull] Func<T,string> toStringFunc)
		{
			if (toStringFunc == null) throw new ArgumentNullException(nameof(toStringFunc));
			var sb = new StringBuilder();
			self.ForEach(it => sb.AppendLine(toStringFunc(it)));
			return sb.ToString();
		}
	}
}
